package com.ftg.learn.bus.lnterceptor;

import com.ftg.learn.bus.entity.LoginUser;
import com.ftg.learn.util.JWTUtil;
import com.ftg.learn.util.ResEntity;
import io.jsonwebtoken.Claims;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 *  登录   处理拦截器
 * @author Guo
 * @date 2022/3/13
 */
public class LoginInterceptor implements HandlerInterceptor {

    /**
     * threadlocal而是一个线程内部的存储类，
     * 可以在指定线程内存储数据，数据存储以后，只有指定线程可以得到存储数据
     * 每个线程持有一个ThreadLocalMap对象。
     * 每一个新的线程Thread都会实例化一个ThreadLocalMap并赋值给成员变量threadLocals，
     * 使用时若已经存在threadLocals则直接使用已经存在的对象。
     */
    public static ThreadLocal<LoginUser> loginUserThreadLocal = new ThreadLocal<LoginUser>();

    /**
     *  preHandle方法是进行处理器拦截用的，
     *  顾名思义，该方法将在Controller处理之前进行调用。
     *  SpringMVC中的Interceptor拦截器是链式的，可以同时存在多个Interceptor，
     *  然后SpringMVC会根据声明的前后顺序一个接一个的执行，
     *  而且所有的Interceptor中的preHandle方法都会在Controller方法调用之前调用。
     *
     * （SpringMVC的这种Interceptor链式结构也是可以进行中断的，
     * 这种中断方式是令preHandle的返回值为false，
     * 当preHandle的返回值为false的时候整个请求就结束了。）
     *
     * 重写preHandle方法，在请求发生前执行。
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = null;
        Cookie[] cookies = request.getCookies();
        Map<String,String> cMap = new HashMap<>();

        if (Objects.isNull(cookies)){
            ResEntity resEntity = ResEntity.LoginFailure("token null");
            JWTUtil.sendJsonMessage(response, resEntity);
//            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return false;
        }
        for(Cookie c : cookies){
            cMap.put(c.getName(),c.getValue());
        }
        System.out.println("------------->"+cMap.get("token"));
        if (Objects.nonNull(cMap.get("token"))) {    //request.getParameter("token")
            //从请求参数拿token ?token=***
//            token = request.getParameter("token");
            token = cMap.get("token");
        }
//        else {
//            //从请求头拿token
//            token = request.getHeader("Authorization");
//        }
        if (Objects.isNull(token)) {
            // 实际 响应给前端，都应该是  未登录 防止黑客攻击。
            ResEntity tokenNull = ResEntity.LoginFailure("token null");
            JWTUtil.sendJsonMessage(response, tokenNull);
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return false;
        }
        Claims claims = JWTUtil.checkToken(token);
        if (Objects.isNull(claims)) {
            ResEntity resEntity = ResEntity.LoginFailure("令牌解析错误或令牌过期 重新登录");
            JWTUtil.sendJsonMessage(response, resEntity);
            return false;
        }
        long id = Long.parseLong(String.valueOf(claims.get("id")));
        String name = String.valueOf(claims.get("name"));
        String ip = String.valueOf(claims.get("ip"));
        // 存到线程池里
        loginUserThreadLocal.set(LoginUser.builder().ip(ip).id(id).name(name).build());
        return true;
    }

}
